#include "gobang.h"

Gobang::Gobang(unsigned int size)
{
    winner = -1;
    this->size = size;
    for (unsigned int i = 0; i < size; ++i) {
        board.emplace_back(size, -1);
    }
}

int Gobang::place(uint8_t r, uint8_t c) {
    if (winner == -1 && board[r][c] == -1) {
        current_player = steps.empty() ? 0 : 1 - current_player;
        board[r][c] = current_player;
        steps.emplace_back(r, c, current_player);
        check_win();
        return 0;
    } else {
        return -1;
    }
}

int Gobang::unplace() {
    if (steps.empty() || winner != -1) {
        return -1;
    } else {
        const auto& step = steps.back();
        uint8_t r = std::get<0>(step);
        uint8_t c = std::get<1>(step);
        steps.pop_back();
        board[r][c] = -1;
        current_player = 1 - current_player;
        return 0;
    }
}

int Gobang::get_winner() {
    return winner;
}

bool Gobang::valid(int r, int c) {
    return r >= 0 && r < size && c >= 0 && c < size;
}

bool Gobang::valid_s(int r, int c, int s) {
    return valid(r, c) && board[r][c] == s;
}

void Gobang::check_win() {
    if (steps.empty()) {
        return;
    }
    uint8_t r = std::get<0>(steps.back());
    uint8_t c = std::get<1>(steps.back());
    int s = current_player;
    std::vector<int> dirs = {1, 0, 0, 1, 1, 1, 1, -1};
    for (uint8_t i = 0; i < dirs.size(); i += 2) {
        int dr = dirs[i];
        int dc = dirs[i+1];
        int pos_len = 1;
        while (valid_s(r + dr*pos_len, c + dc*pos_len, s)) pos_len++;
        int neg_len = 1;
        while (valid_s(r - dr*neg_len, c - dc*neg_len, s)) neg_len++;
        int len = pos_len + neg_len - 1;
        if (len >= 5) {
            winner = current_player;
            return;
        }
    }
}

int Gobang::get_status(uint8_t r, uint8_t c) {
    return board[r][c];
}

